Skip to content

Validate Content-Type by parsed media type instead of substring match (v1.x)#2444

Merged
felixweinberger merged 3 commits into
v1.xfrom
fweinberger/v1x-content-type-media-type
Jul 6, 2026
Merged

Validate Content-Type by parsed media type instead of substring match (v1.x)#2444
felixweinberger merged 3 commits into
v1.xfrom
fweinberger/v1x-content-type-media-type

Conversation

@felixweinberger

Copy link
Copy Markdown
Contributor

Backport of #2441 to the v1.x line.

Content-Type validation in the web-standard Streamable HTTP server transport matched the raw header as a substring (ct.includes('application/json')), which misclassifies values whose media type is not application/json (for example text/plain; a=application/json) and wrongly rejects valid case variants. The client's response dispatch used the same pattern.

Motivation and Context

Content-Type is a media type plus optional parameters (RFC 9110); comparisons must use the parsed media type. This mirrors the change on main: parse via the content-type package (already a dependency, used correctly by the SSE transport), with a media-type fallback for malformed parameter sections so unambiguous values like application/json; keep working. The Node transport wraps the web-standard transport, so one change covers both.

How Has This Been Tested?

  • New unit matrix for the helper plus transport tests pinning: non-JSON media types answer 415 without dispatch; parameters, case variants, and malformed-parameter values whose media type is application/json are served; absent and joined duplicate headers answer 415.
  • Full suite (1606 tests), typecheck, and lint pass; HTTP e2e scenarios pass.

Breaking Changes

Stricter for non-conforming clients only; the 415 response body and error code bytes are unchanged. One leniency gain: case variants are now accepted per RFC 9110.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

The Streamable HTTP server gate and the client response dispatch matched
Content-Type with a substring search, which accepts values whose media type
is different (e.g. `text/plain; a=application/json`) and rejects valid case
variants like `Application/JSON`. Parse the header with the content-type
package instead, falling back to the segment before the first `;` when the
parameter section is malformed, so unambiguous values such as
`application/json;` keep working. The 415/-32000 error shape and message
bytes are unchanged. This mirrors the equivalent change on main.
@felixweinberger felixweinberger requested a review from a team as a code owner July 6, 2026 19:27
@changeset-bot

changeset-bot Bot commented Jul 6, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 7ecf52e

The changes in this PR will be included in the next version bump.

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@pkg-pr-new

pkg-pr-new Bot commented Jul 6, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@modelcontextprotocol/sdk@2444

commit: 7ecf52e

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't find any bugs — the media-type parsing helper, transport changes, and test matrix all look correct — but this changes runtime validation behavior in the core Streamable HTTP transport (server 415 handling and client response dispatch), so it's worth a human maintainer's look for interop implications.

Extended reasoning...

Overview

This PR (a v1.x backport of #2441) replaces substring-based Content-Type checks with parsed media-type comparison. It adds a new shared helper (src/shared/mediaType.ts) built on the existing content-type dependency with a fallback for malformed parameter sections, applies it to POST Content-Type validation in WebStandardStreamableHTTPServerTransport and to response dispatch in the Streamable HTTP client, adds an ESLint no-restricted-syntax rule to prevent regressions, and includes a thorough unit/transport test matrix plus a changeset.

Security risks

The change is strictly a tightening of input validation: values like text/plain; a=application/json are now correctly rejected with 415 instead of being dispatched. No injection, auth, or data-exposure surface is introduced. The fallback parser for malformed parameter sections is conservative (returns no essence for joined duplicate headers), and I verified the only remaining substring check in src/ (the Accept header list check) is intentionally exempted with a lint disable.

Level of scrutiny

The logic and tests look correct, but this touches the core Streamable HTTP transport on both the server (request rejection path) and the client (response content-type dispatch). The client-side change means responses whose Content-Type merely contained the substring but is not exactly application/json or text/event-stream as a media type will now be treated as unexpected — stricter behavior that could in principle affect interop with non-conforming servers on the stable v1.x line. That behavior/compatibility judgment on a widely-used code path is one a maintainer should confirm, so I'm not shadow-approving.

Other factors

Test coverage is strong: a new helper unit matrix and transport-level tests pinning 415-without-dispatch for non-JSON media types, acceptance of parameters/case variants/malformed parameter sections, and rejection of joined duplicate headers. The PR mirrors an already-accepted change on main, which reduces design risk, but the backport target (v1.x patch release) raises the bar for behavioral changes.

@felixweinberger felixweinberger merged commit 69749aa into v1.x Jul 6, 2026
12 of 13 checks passed
@felixweinberger felixweinberger deleted the fweinberger/v1x-content-type-media-type branch July 6, 2026 20:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants